﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Linq;
using System.Text;
using Microsoft.ServiceHosting.ServiceRuntime;
using HollywoodHackers.Storage.Queue;
using HollywoodHackers.Storage.Table;
using Microsoft.Samples.ServiceHosting.StorageClient;

namespace HollywoodHackers.Worker
{
    public class WorkerRole : RoleEntryPoint
    {
        StorageAccountInfo queueStorageAccount;
        StorageAccountInfo tableStorageAccount;
        QueueStorage queueStorage;
        MessageQueue notifyQueue;
        MessageQueue cartQueue;
        string queueName;
        string cartQueueName;
        UserNotificationRepository toastRepository;

        public override void Start()
        {
            queueStorageAccount = StorageAccountInfo.GetDefaultQueueStorageAccountFromConfiguration();
            tableStorageAccount = StorageAccountInfo.GetDefaultTableStorageAccountFromConfiguration();

            queueName = QueueNames.SystemMessages;
            cartQueueName = QueueNames.ShoppingCart;
            toastRepository = new UserNotificationRepository(null, null, tableStorageAccount);
            // This is a sample worker implementation. Replace with your logic.
            RoleManager.WriteToLog("Information", "Worker Process entry point called");

            InitQueue();
            while (true)
            {
                Thread.Sleep(10000);
                RoleManager.WriteToLog("Information", "Working");

                ProcessNewSystemMessages();

                ProcessShoppingCarts();
            }
        }

        public void InitQueue()
        {
            queueStorage = QueueStorage.Create(queueStorageAccount);
            queueStorage.RetryPolicy = RetryPolicies.RetryN(2, TimeSpan.FromMilliseconds(100));

            notifyQueue = queueStorage.GetQueue(queueName);
            bool exists;
            bool res = notifyQueue.CreateQueue(out exists);
            if (!exists)
            {
                RoleManager.WriteToLog("Information",
                    string.Format("Created Queue {0} for First Time.", queueName));
            }

            cartQueue = queueStorage.GetQueue(cartQueueName);
            res = cartQueue.CreateQueue(out exists);
            if (!exists)
            {
                RoleManager.WriteToLog("Information",
                    string.Format("Created Queue {0} for First Time.", cartQueueName));
            }
        }

        public void ProcessShoppingCarts()
        {
            Message m = cartQueue.GetMessage(120);
            while (m != null)
            {
                ShoppingCart cart = ShoppingCart.FromMessage<ShoppingCart>(m);

                /*
                 * At this point, we would normally do real processing on the cart
                 * like contacting third parties, sending it to Biztalk, or simply
                 * storing it in table storage
                 */

                RoleManager.WriteToLog("Information",
                    string.Format("About to submit user notification for cart with {0} items for user {1}",
                    cart.CartItems.Length, cart.UserName));

                // Notify the user that their cart has been processed.
                toastRepository.AddNotification(new UserTextNotification()
                {
                    MessageText = string.Format(
                                    "Your shopping cart containing {0} items has been processed.",
                                    cart.CartItems.Length),
                    MessageDate = DateTime.Now
                }, cart.UserName);
                RoleManager.WriteToLog("Information",
                    "Notified user that cart has been processed.");
                cartQueue.DeleteMessage(m);
                m = cartQueue.GetMessage(120);
            }
        }

        public void ProcessNewSystemMessages()
        {
            IEnumerable<Message> newMessages = notifyQueue.GetMessages(20, 120);
            if (newMessages != null)
            {
                foreach (Message m in newMessages)
                {
                    SystemMessage sysMessage = SystemMessage.FromMessage<SystemMessage>(m);
                    toastRepository.AddNotification(new UserTextNotification()
                    {
                        MessageText = sysMessage.MessageText,
                        MessageDate = sysMessage.CreatedOn
                    }, sysMessage.TargetUserName);
                    notifyQueue.DeleteMessage(m);
                    RoleManager.WriteToLog("Information",
                        "Moved queued notification to user toast table.");
                }
            }
        }

        public override RoleStatus GetHealthStatus()
        {
            // This is a sample worker implementation. Replace with your logic.
            return RoleStatus.Healthy;
        }
    }
}
